From: Keir Fraser Date: Fri, 5 Jun 2009 08:27:18 +0000 (+0100) Subject: VT-d: define a macro for waiting hardare completion X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~13793 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=2de77a2754814ce47a9e36422edf9de375ab616f;p=xen.git VT-d: define a macro for waiting hardare completion When set some registers of VT-d, it must wait for hardware completion. There are lots of duplicated code to do that. This patch defines a macro for it, thus it is much cleaner. Signed-off-by: Weidong Han --- diff --git a/xen/drivers/passthrough/vtd/dmar.h b/xen/drivers/passthrough/vtd/dmar.h index 3664b19d21..f0bfb541a5 100644 --- a/xen/drivers/passthrough/vtd/dmar.h +++ b/xen/drivers/passthrough/vtd/dmar.h @@ -90,6 +90,20 @@ void dmar_scope_remove_buses(struct dmar_scope *scope, u16 sec, u16 sub); #define DMAR_OPERATION_TIMEOUT MILLISECS(1000) +#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \ +do { \ + s_time_t start_time = NOW(); \ + while (1) { \ + sts = op(iommu->reg, offset); \ + if ( cond ) \ + break; \ + if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) \ + panic("%s:%d:%s: DMAR hardware is malfunctional\n", \ + __FILE__, __LINE__, __func__); \ + cpu_relax(); \ + } \ +} while (0) + int vtd_hw_check(void); void disable_pmr(struct iommu *iommu); int is_usb_device(u8 bus, u8 devfn); diff --git a/xen/drivers/passthrough/vtd/intremap.c b/xen/drivers/passthrough/vtd/intremap.c index e918708cd1..083faa486d 100644 --- a/xen/drivers/passthrough/vtd/intremap.c +++ b/xen/drivers/passthrough/vtd/intremap.c @@ -534,7 +534,7 @@ void msi_msg_write_remap_rte( int enable_intremap(struct iommu *iommu) { struct ir_ctrl *ir_ctrl; - s_time_t start_time; + u32 sts; ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap); @@ -564,38 +564,22 @@ int enable_intremap(struct iommu *iommu) iommu->gcmd |= DMA_GCMD_SIRTP; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); - /* Make sure hardware complete it */ - start_time = NOW(); - while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_SIRTPS) ) - { - if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) - panic("Cannot set SIRTP field for interrupt remapping\n"); - cpu_relax(); - } - + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + (sts & DMA_GSTS_SIRTPS), sts); + /* enable comaptiblity format interrupt pass through */ iommu->gcmd |= DMA_GCMD_CFI; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); - start_time = NOW(); - while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) ) - { - if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) - panic("Cannot set CFI field for interrupt remapping\n"); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + (sts & DMA_GSTS_CFIS), sts); /* enable interrupt remapping hardware */ iommu->gcmd |= DMA_GCMD_IRE; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); - start_time = NOW(); - while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) ) - { - if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) - panic("Cannot set IRE field for interrupt remapping\n"); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + (sts & DMA_GSTS_IRES), sts); /* After set SIRTP, we should do globally invalidate the IEC */ iommu_flush_iec_global(iommu); @@ -605,18 +589,13 @@ int enable_intremap(struct iommu *iommu) void disable_intremap(struct iommu *iommu) { - s_time_t start_time; + u32 sts; ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap); iommu->gcmd &= ~(DMA_GCMD_SIRTP | DMA_GCMD_CFI | DMA_GCMD_IRE); dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); - start_time = NOW(); - while ( dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES ) - { - if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) - panic("Cannot clear IRE field for interrupt remapping\n"); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + !(sts & DMA_GSTS_IRES), sts); } diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 50e801fe69..96c7ef26be 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -230,7 +230,6 @@ static void iommu_flush_write_buffer(struct iommu *iommu) { u32 val; unsigned long flag; - s_time_t start_time; if ( !rwbf_quirk && !cap_rwbf(iommu->cap) ) return; @@ -240,17 +239,9 @@ static void iommu_flush_write_buffer(struct iommu *iommu) dmar_writel(iommu->reg, DMAR_GCMD_REG, val); /* Make sure hardware complete it */ - start_time = NOW(); - for ( ; ; ) - { - val = dmar_readl(iommu->reg, DMAR_GSTS_REG); - if ( !(val & DMA_GSTS_WBFS) ) - break; - if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) - panic("%s: DMAR hardware is malfunctional," - " please disable IOMMU\n", __func__); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + !(val & DMA_GSTS_WBFS), val); + spin_unlock_irqrestore(&iommu->register_lock, flag); } @@ -263,7 +254,6 @@ static int flush_context_reg( struct iommu *iommu = (struct iommu *) _iommu; u64 val = 0; unsigned long flag; - s_time_t start_time; /* * In the non-present entry flush case, if hardware doesn't cache @@ -301,17 +291,9 @@ static int flush_context_reg( dmar_writeq(iommu->reg, DMAR_CCMD_REG, val); /* Make sure hardware complete it */ - start_time = NOW(); - for ( ; ; ) - { - val = dmar_readq(iommu->reg, DMAR_CCMD_REG); - if ( !(val & DMA_CCMD_ICC) ) - break; - if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) - panic("%s: DMAR hardware is malfunctional," - " please disable IOMMU\n", __func__); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG, dmar_readq, + !(val & DMA_CCMD_ICC), val); + spin_unlock_irqrestore(&iommu->register_lock, flag); /* flush context entry will implicitly flush write buffer */ return 0; @@ -352,7 +334,6 @@ static int flush_iotlb_reg(void *_iommu, u16 did, int tlb_offset = ecap_iotlb_offset(iommu->ecap); u64 val = 0, val_iva = 0; unsigned long flag; - s_time_t start_time; /* * In the non-present entry flush case, if hardware doesn't cache @@ -399,17 +380,8 @@ static int flush_iotlb_reg(void *_iommu, u16 did, dmar_writeq(iommu->reg, tlb_offset + 8, val); /* Make sure hardware complete it */ - start_time = NOW(); - for ( ; ; ) - { - val = dmar_readq(iommu->reg, tlb_offset + 8); - if ( !(val & DMA_TLB_IVT) ) - break; - if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) - panic("%s: DMAR hardware is malfunctional," - " please disable IOMMU\n", __func__); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, (tlb_offset + 8), dmar_readq, + !(val & DMA_TLB_IVT), val); spin_unlock_irqrestore(&iommu->register_lock, flag); /* check IOTLB invalidation granularity */ @@ -578,7 +550,6 @@ static int iommu_set_root_entry(struct iommu *iommu) { u32 cmd, sts; unsigned long flags; - s_time_t start_time; spin_lock(&iommu->lock); @@ -597,18 +568,8 @@ static int iommu_set_root_entry(struct iommu *iommu) dmar_writel(iommu->reg, DMAR_GCMD_REG, cmd); /* Make sure hardware complete it */ - start_time = NOW(); - for ( ; ; ) - { - sts = dmar_readl(iommu->reg, DMAR_GSTS_REG); - if ( sts & DMA_GSTS_RTPS ) - break; - if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) - panic("%s: DMAR hardware is malfunctional," - " please disable IOMMU\n", __func__); - cpu_relax(); - } - + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + (sts & DMA_GSTS_RTPS), sts); spin_unlock_irqrestore(&iommu->register_lock, flags); return 0; @@ -618,25 +579,16 @@ static void iommu_enable_translation(struct iommu *iommu) { u32 sts; unsigned long flags; - s_time_t start_time; dprintk(XENLOG_INFO VTDPREFIX, "iommu_enable_translation: iommu->reg = %p\n", iommu->reg); spin_lock_irqsave(&iommu->register_lock, flags); iommu->gcmd |= DMA_GCMD_TE; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); + /* Make sure hardware complete it */ - start_time = NOW(); - for ( ; ; ) - { - sts = dmar_readl(iommu->reg, DMAR_GSTS_REG); - if ( sts & DMA_GSTS_TES ) - break; - if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) - panic("%s: DMAR hardware is malfunctional," - " please disable IOMMU\n", __func__); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + (sts & DMA_GSTS_TES), sts); /* Disable PMRs when VT-d engine takes effect per spec definition */ disable_pmr(iommu); @@ -647,24 +599,14 @@ static void iommu_disable_translation(struct iommu *iommu) { u32 sts; unsigned long flags; - s_time_t start_time; spin_lock_irqsave(&iommu->register_lock, flags); iommu->gcmd &= ~ DMA_GCMD_TE; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); /* Make sure hardware complete it */ - start_time = NOW(); - for ( ; ; ) - { - sts = dmar_readl(iommu->reg, DMAR_GSTS_REG); - if ( !(sts & DMA_GSTS_TES) ) - break; - if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) - panic("%s: DMAR hardware is malfunctional," - " please disable IOMMU\n", __func__); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + !(sts & DMA_GSTS_TES), sts); spin_unlock_irqrestore(&iommu->register_lock, flags); } diff --git a/xen/drivers/passthrough/vtd/qinval.c b/xen/drivers/passthrough/vtd/qinval.c index 5df55dcbd6..ebd873eb58 100644 --- a/xen/drivers/passthrough/vtd/qinval.c +++ b/xen/drivers/passthrough/vtd/qinval.c @@ -418,9 +418,9 @@ static int flush_iotlb_qi( int enable_qinval(struct iommu *iommu) { - s_time_t start_time; struct qi_ctrl *qi_ctrl; struct iommu_flush *flush; + u32 sts; qi_ctrl = iommu_qi_ctrl(iommu); flush = iommu_get_flush(iommu); @@ -458,13 +458,8 @@ int enable_qinval(struct iommu *iommu) dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); /* Make sure hardware complete it */ - start_time = NOW(); - while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_QIES) ) - { - if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) - panic("Cannot set QIE field for queue invalidation\n"); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + (sts & DMA_GSTS_QIES), sts); qinval_enabled = 1; return 0; @@ -472,7 +467,7 @@ int enable_qinval(struct iommu *iommu) void disable_qinval(struct iommu *iommu) { - s_time_t start_time; + u32 sts; ASSERT(ecap_queued_inval(iommu->ecap) && iommu_qinval); @@ -480,11 +475,6 @@ void disable_qinval(struct iommu *iommu) dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); /* Make sure hardware complete it */ - start_time = NOW(); - while ( dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_QIES ) - { - if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) - panic("Cannot clear QIE field for queue invalidation\n"); - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, + !(sts & DMA_GSTS_QIES), sts); } diff --git a/xen/drivers/passthrough/vtd/utils.c b/xen/drivers/passthrough/vtd/utils.c index 9854d14671..83b6126c57 100644 --- a/xen/drivers/passthrough/vtd/utils.c +++ b/xen/drivers/passthrough/vtd/utils.c @@ -38,27 +38,16 @@ int is_usb_device(u8 bus, u8 devfn) /* Disable vt-d protected memory registers. */ void disable_pmr(struct iommu *iommu) { - s_time_t start_time; - unsigned int val; + u32 val; val = dmar_readl(iommu->reg, DMAR_PMEN_REG); if ( !(val & DMA_PMEN_PRS) ) return; dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM); - start_time = NOW(); - for ( ; ; ) - { - val = dmar_readl(iommu->reg, DMAR_PMEN_REG); - if ( (val & DMA_PMEN_PRS) == 0 ) - break; - - if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) - panic("Disable PMRs timeout\n"); - - cpu_relax(); - } + IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG, dmar_readl, + !(val & DMA_PMEN_PRS), val); dprintk(XENLOG_INFO VTDPREFIX, "Disabled protected memory registers\n");